package fss

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"
)

type (
	HttpClient struct {
		Host   string
		Secret string
		Client *http.Client
	}
)

func NewHttpClient(host string, secret string) *HttpClient {
	return &HttpClient{
		Secret: secret,
		Host:   host,
		Client: &http.Client{Timeout: time.Second * 3},
	}
}

func (c *HttpClient) Request(route string, query ...string) ([]byte, error) {
	if len(route) == 0 {
		return nil, errors.New("empty route")
	}
	var address = c.Host
	if route[0] == '/' {
		address += route
	} else {
		address += "/" + route
	}
	address += "?secret=" + c.Secret
	if len(query) > 0 {
		address += "&" + query[0]
	}
	response, err := c.Client.Get(address)
	if err != nil {
		return nil, err
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			return
		}
	}(response.Body)
	if response.StatusCode != http.StatusOK {
		return nil, errors.New(response.Status)
	}
	return io.ReadAll(response.Body)
}

// GetApiList 获取服务器api列表(getApiList)
func (c *HttpClient) GetApiList() *Response[[]string] {
	data, err := c.Request(routeGetAplList)
	if err != nil {
		return RequestRouteErr[[]string](routeGetAplList, err)
	}
	return Bytes[[]string](data).Unmarshal()
}

// GetThreadsLoad 获取网络线程负载(getThreadsLoad)
func (c *HttpClient) GetThreadsLoad() *Response[[]map[string]int] {
	data, err := c.Request(routeGetThreadsLoad)
	if err != nil {
		return RequestRouteErr[[]map[string]int](routeGetThreadsLoad, err)
	}
	return Bytes[[]map[string]int](data).Unmarshal()
}

// GetStatistic 获取主要对象个数(getStatistic)
func (c *HttpClient) GetStatistic() *Response[map[string]int] {
	data, err := c.Request(routeGetStatistic)
	if err != nil {
		return RequestRouteErr[map[string]int](routeGetStatistic, err)
	}
	return Bytes[map[string]int](data).Unmarshal()
}

// GetWorkThreadsLoad 获取后台线程负载(getWorkThreadsLoad)
func (c *HttpClient) GetWorkThreadsLoad() *Response[[]map[string]int] {
	data, err := c.Request(routeGetWorkThreadsLoad)
	if err != nil {
		return RequestRouteErr[[]map[string]int](routeGetWorkThreadsLoad, err)
	}
	return Bytes[[]map[string]int](data).Unmarshal()
}

// GetServerConfig 获取服务器配置(getServerConfig)
func (c *HttpClient) GetServerConfig() *Response[[]map[string]string] {
	data, err := c.Request(routeGetServerConfig)
	if err != nil {
		return RequestRouteErr[[]map[string]string](routeGetServerConfig, err)
	}
	return Bytes[[]map[string]string](data).Unmarshal()
}

// SetServerConfig 获取服务器配置(setServerConfig)
func (c *HttpClient) SetServerConfig(key, value string) *Response[any] {
	data, err := c.Request(routeSetServerConfig, fmt.Sprintf("%s=%s", key, value))
	if err != nil {
		return RequestRouteErr[any](routeSetServerConfig, err)
	}
	return Bytes[any](data).Unmarshal()
}

// RestartServer 重启服务器(restartServer)
func (c *HttpClient) RestartServer() *Response[any] {
	data, err := c.Request(routeRestartServer)
	if err != nil {
		return RequestRouteErr[any](routeRestartServer, err)
	}
	return Bytes[any](data).Unmarshal()
}

// GetMediaList 获取流列表(getMediaList)
func (c *HttpClient) GetMediaList() *Response[[]MediaInfo] {
	data, err := c.Request(routeGetMediaList)
	if err != nil {
		return RequestRouteErr[[]MediaInfo](routeGetMediaList, err)
	}
	return Bytes[[]MediaInfo](data).Unmarshal()
}

// CloseStream 关断单个流(close_stream)
//
// schema	Y	协议，例如 rtsp 或 rtmp
// vhost	Y	虚拟主机，例如__defaultVhost__
// app	    Y	应用名，例如 live
// stream	Y	流 id，例如 test
//
// Deprecated: see CloseStreams
func (c *HttpClient) CloseStream(schema, vhost, app, stream string) *Response[any] {
	data, err := c.Request(routeCloseStream, fmt.Sprintf("schema=%s&vhost=%s&app=%s&stream=%s", schema, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[any](routeCloseStream, err)
	}
	return Bytes[any](data).Unmarshal()
}

// CloseStreams 批量关断流(close_streams)
// schema	N	协议，例如 rtsp 或 rtmp
// vhost	N	虚拟主机，例如__defaultVhost__
// app      N	应用名，例如 live
// stream	N	流 id，例如 test
func (c *HttpClient) CloseStreams(schema, vhost, app, stream string) *Response[any] {
	data, err := c.Request(routeCloseStreams, fmt.Sprintf("schema=%s&vhost=%s&app=%s&stream=%s", schema, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[any](routeCloseStreams, err)
	}
	return Bytes[any](data).Unmarshal()
}

// GetAllSession 获取所有 TcpSession 列表(获取所有 tcp 客户端相关信息)
func (c *HttpClient) GetAllSession() *Response[[]map[string]any] {
	data, err := c.Request(routeGetAllSession)
	if err != nil {
		return RequestRouteErr[[]map[string]any](routeGetAllSession, err)
	}
	return Bytes[[]map[string]any](data).Unmarshal()
}

// KickSession 断开 tcp 连接，比如说可以断开 rtsp、rtmp 播放器等
func (c *HttpClient) KickSession(id string) *Response[any] {
	data, err := c.Request(routeKickSession, fmt.Sprintf("id=%s", id))
	if err != nil {
		return RequestRouteErr[any](routeKickSession, err)
	}
	return Bytes[any](data).Unmarshal()
}

// KickSessions 断开 tcp 连接，比如说可以断开 rtsp、rtmp 播放器等
func (c *HttpClient) KickSessions() *Response[any] {
	data, err := c.Request(routeKickSessions)
	if err != nil {
		return RequestRouteErr[any](routeKickSessions, err)
	}
	return Bytes[any](data).Unmarshal()
}

// AddStreamProxy 动态添加 rtsp/rtmp/hls/http-ts/http-flv 拉流代理(只支持 H264/H265/aac/G711/opus 负载)
// vhost	          string	添加的流的虚拟主机，例如__defaultVhost__	Y
// app	              string	添加的流的应用名，例如 live	Y
// stream	          string	添加的流的 id 名，例如 test	Y
// url	              string	拉流地址，例如 rtmp://live.hkstv.hk.lxdns.com/live/hks2	Y
// retry_count	        int	    拉流重试次数，默认为-1 无限重试	N
// rtp_type	int	        rtsp    拉流时，拉流方式，0：tcp，1：udp，2：组播	N
// timeout_sec	        int	    拉流超时时间，单位秒，float 类型	N
// enable_hls	        bool	是否转换成 hls-mpegts 协议	N
// enable_hls_fmp4	    bool	是否转换成 hls-fmp4 协议	N
// enable_mp4	        bool	是否允许 mp4 录制	N
// enable_rtsp	        bool	是否转 rtsp 协议	N
// enable_rtmp	        bool	是否转 rtmp/flv 协议	N
// enable_ts	        bool	是否转 http-ts/ws-ts 协议	N
// enable_fmp4	        bool	是否转 http-fmp4/ws-fmp4 协议	N
// hls_demand	        bool	该协议是否有人观看才生成	N
// rtsp_demand	        bool	该协议是否有人观看才生成	N
// rtmp_demand	        bool	该协议是否有人观看才生成	N
// ts_demand	        bool	该协议是否有人观看才生成	N
// fmp4_demand	        bool	该协议是否有人观看才生成	N
// enable_audio	        bool	转协议时是否开启音频	N
// add_mute_audio	    bool	转协议时，无音频是否添加静音 aac 音频	N
// mp4_save_path	    string	mp4 录制文件保存根目录，置空使用默认	N
// mp4_max_second       int	    mp4 录制切片大小，单位秒	N
// mp4_as_player	    bool	MP4 录制是否当作观看者参与播放人数计数	N
// hls_save_path	    string	hls 文件保存保存根目录，置空使用默认	N
// modify_stamp	        int	    该流是否开启时间戳覆盖(0:绝对时间戳/1:系统时间戳/2:相对时间戳)	N
// auto_close	        bool	无人观看是否自动关闭流(不触发无人观看 hook)	N
func (c *HttpClient) AddStreamProxy(model *StreamModel) *Response[ResponseAddStreamProxy] {
	data, err := c.Request(routeAddStreamProxy, model.ToQuery())
	if err != nil {
		return RequestRouteErr[ResponseAddStreamProxy](routeAddStreamProxy, err)
	}
	return Bytes[ResponseAddStreamProxy](data).Unmarshal()
}

// AddDefaultStreamProxy 动态添加拉流代理
func (c *HttpClient) AddDefaultStreamProxy(app, stream, url string) *Response[ResponseAddStreamProxy] {
	model := DefaultStreamModel(app, stream, url)
	data, err := c.Request(routeAddStreamProxy, model.ToQuery())
	if err != nil {
		return RequestRouteErr[ResponseAddStreamProxy](routeAddStreamProxy, err)
	}
	return Bytes[ResponseAddStreamProxy](data).Unmarshal()
}

// GetMp4RecordFile 搜索文件系统，获取流对应的录像文件列表或日期文件夹列表
// 流的录像日期，格式为 2020-02-01,如果不是完整的日期，那么是搜索录像文件夹列表，否则搜索对应日期下的 mp4 文件列表
func (c *HttpClient) GetMp4RecordFile(vhost, app, stream, period string) *Response[ResponseGetMp4RecordFile] {
	data, err := c.Request(routeGetMp4RecordFile, fmt.Sprintf("vhost=%s&app=%s&stream=%s&period=%s", vhost, app, stream, period))
	if err != nil {
		return RequestRouteErr[ResponseGetMp4RecordFile](routeGetMp4RecordFile, err)
	}
	return Bytes[ResponseGetMp4RecordFile](data).Unmarshal()
}

// StartRecord 开始录制 hls 或 MP4
// t: 0 为 hls，1 为 mp4
func (c *HttpClient) StartRecord(t, vhost, app, stream string) *Response[any] {
	data, err := c.Request(routeStartRecord, fmt.Sprintf("type=%s&vhost=%s&app=%s&stream=%s", t, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[any](routeStartRecord, err)
	}
	return Bytes[any](data).Unmarshal()
}

// StartDefaultMP4Record 开始录制 hls 或 MP4
func (c *HttpClient) StartDefaultMP4Record(app, stream string) *Response[any] {
	data, err := c.Request(routeStartRecord, fmt.Sprintf("type=1&vhost=__defaultVhost__&app=%s&stream=%s", app, stream))
	if err != nil {
		return RequestRouteErr[any](routeStartRecord, err)
	}
	return Bytes[any](data).Unmarshal()
}

// StopRecord 停止录制流
// t: 0 为 hls，1 为 mp4
func (c *HttpClient) StopRecord(t, vhost, app, stream string) *Response[any] {
	data, err := c.Request(routeStopRecord, fmt.Sprintf("type=%s&vhost=%s&app=%s&stream=%s", t, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[any](routeStopRecord, err)
	}
	return Bytes[any](data).Unmarshal()
}

// StopDefaultMp4Record 停止录制流
func (c *HttpClient) StopDefaultMp4Record(app, stream string) *Response[any] {
	data, err := c.Request(routeStopRecord, fmt.Sprintf("type=1&vhost=__defaultVhost__&app=%s&stream=%s", app, stream))
	if err != nil {
		return RequestRouteErr[any](routeStopRecord, err)
	}
	return Bytes[any](data).Unmarshal()
}

// IsRecording 获取流录制状态
// t: 0 为 hls，1 为 mp4
func (c *HttpClient) IsRecording(t, vhost, app, stream string) *Response[any] {
	data, err := c.Request(routeIsRecording, fmt.Sprintf("type=%s&vhost=%s&app=%s&stream=%s", t, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[any](routeIsRecording, err)
	}
	return Bytes[any](data).Unmarshal()
}

// IsDefaultMp4Recording 获取流录制状态
func (c *HttpClient) IsDefaultMp4Recording(app, stream string) *Response[any] {
	data, err := c.Request(routeIsRecording, fmt.Sprintf("type=1&vhost=__defaultVhost__&app=%s&stream=%s", app, stream))
	if err != nil {
		return RequestRouteErr[any](routeIsRecording, err)
	}
	return Bytes[any](data).Unmarshal()
}

// GetSnap 获取截图或生成实时截图并返回
func (c *HttpClient) GetSnap(url, timeoutSec, expireSec string) *Response[any] {
	data, err := c.Request(routeGetSnap, fmt.Sprintf("url=%s&timeout_sec=%s&expire_sec=%s", url, timeoutSec, expireSec))
	if err != nil {
		return RequestRouteErr[any](routeGetSnap, err)
	}
	return Bytes[any](data).Unmarshal()
}

// Version 获取版本信息，如分支，commit id, 编译时间
func (c *HttpClient) Version() *Response[ResponseVersion] {
	data, err := c.Request(routeVersion)
	if err != nil {
		return RequestRouteErr[ResponseVersion](routeVersion, err)
	}
	return Bytes[ResponseVersion](data).Unmarshal()
}

// GetMediaPlayerList 获取某个流观看者列表
func (c *HttpClient) GetMediaPlayerList(schema, vhost, app, stream string) *Response[ResponseGetMp4RecordFile] {
	data, err := c.Request(routeGetMediaPlayerList, fmt.Sprintf("schema=%s&vhost=%s&app=%s&stream=%s", schema, vhost, app, stream))
	if err != nil {
		return RequestRouteErr[ResponseGetMp4RecordFile](routeGetMediaPlayerList, err)
	}
	return Bytes[ResponseGetMp4RecordFile](data).Unmarshal()
}
